﻿using System.Collections;
using KinonekoSoftware.Extensions.Strings.Core;

namespace KinonekoSoftware.Extensions.Strings.SearchModels.TrieTree
{

    public class TrieTreeGlossaryProvider : IGlossaryProvider, ITrieTreeGlossaryProviderRoot, IEnumerable<string>
    {
        private int _version;
        private int _count;

        private readonly Node _root = new Node('$') { Parent = null, Depth = 1 };

        public void Add(string key)
        {
            if (string.IsNullOrEmpty(key))
            {
                return;
            }


            //
            //
            var node = key.Aggregate(_root, (current, ch) => current.GetOrCreate(ch));


            //
            //
            if (!node.IsWordEnd)
            {
                node.IsWordEnd = true;
                _count++;
                _version++;
            }


        }

        public void Remove(string key)
        {
            if (string.IsNullOrEmpty(key))
            {
                return;
            }

            var stack  = new Stack<Node>();
            var node   = _root;
            var exists = false;

            foreach (var ch in key)
            {
                if (node.Children.TryGetValue(ch, out var child))
                {
                    exists = true;
                    node   = child;
                    stack.Push(child);
                }
                else
                {
                    exists = false;
                    break;
                }
            }

            if (exists)
            {
                if (stack.Count > 1)
                {
                    while (stack.Count > 1)
                    {
                        var current = stack.Pop();
                        var parent  = stack.Peek();

                        if (!current.HasChildren)
                        {
                            parent.Remove(current);
                        }
                    }
                }
                else
                {
                    //
                    //
                    _root.Remove(stack.Pop());
                }


                _version++;
            }

        }

        public void Clear()
        {
            _version++;
            _root.Children.Clear();
        }
        
        
        
        public IEnumerator<string> GetEnumerator()
        {
            var array = TrieTreeGlossaryProviderEnumerator.GetArray(this);

            foreach (var item in array)
            {
                yield return item;
            }
        }

        public int Count   => _count;
        public int Version => _version;

        
        Node ITrieTreeGlossaryProviderRoot.Root => _root;
        
        
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }
}